import os
import sys
import json
import shutil
import unittest
from copy import deepcopy

# _BASE_DIR is the root directory of the tool and needs to be added to sys.path.
_BASE_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(_BASE_DIR)

from framework.config_parser import ConfigFileParser
from framework.options_combiner import OptionCombiner
from common.benchmark_var import ConfigOptions as Options
from framework.report.var_report import JSONFileKey as Key, ReportContentKey as ReportKey
from framework.report.pre_report import PreReport, ReportData


BM_SUITE_1 = {'ServerSuite': {'score': ''}}
BM_SUITE_2 = {'ServerSuite': {'MemSuite': {'desc': '', 'score': '2.14'}, 'score': ''}}
BM_DETAIL_1 = {'DesktopSuite':
               {'CPUSuite':  {'workloads':
                {'scimarkj_fft': {'desc': '', 'unit': '', 'score': '0.00', 'elapsed_time': '0.028',
                                  'index': '0.00', 'valid': False}}, 'score': '0.00'}}}
BM_DETAIL_2 = {'CPUSuite': {'workloads': {'scimarkj_fft':
               {'desc': '', 'unit': '', 'score': '0.00', 'elapsed_time': '0.028', 'index': '0.00', 'valid': False}},
                            'score': '0.00'}}
SUB_SUITE_1 = {'sub_suites_total': [{'name': 'CPUSuite', 'desc': None, 'score': 0}], 'CPUSuite': {}}
SUB_SUITE_2 = {'sub_suites_total': [{'name': 'CPUSuite', 'desc': None, 'score': 0}],
               'CPUSuite': {'workloads':
                            {'scimarkj_fft': {'desc': '', 'unit': '', 'score': 0, 'elapsed_time': None,
                                              'index': 0, 'valid': True}}}}
WORKLOAD_INFO = {'workloads': {'redis': {'desc': 'redis benchmark', 'unit': 'rps', 'score': '1136581.88',
                               'elapsed_time': '124.287', 'index': '17.01', 'valid': True}}, 'score': '17.01'}


class PreReportTestCase(unittest.TestCase):
    """
    Test the processing of json data.
    """
    CUR_DIR = os.path.dirname(os.path.abspath(__file__))
    TEST_DATA_DIR = "test_data"

    @classmethod
    def setUpClass(cls):
        cls.result_dir = os.path.join(cls.CUR_DIR, "pre_report_data")
        cls.test_data_dir = os.path.join(cls.CUR_DIR, cls.TEST_DATA_DIR)
        cls.base_json_data = {"GCBS.system_content": {},
                              "GCBS.benchmark_content": {
                                    "GCBS.benchmark.summary": {},
                                    "GCBS.benchmark.detail": []}}
        config_file = os.path.join(cls.CUR_DIR, "../config", "config_sample.ini")
        config_opts = ConfigFileParser().parse_ini(config_file)
        cls.option = OptionCombiner().combine_options(config_opts, {})

    @classmethod
    def tearDownClass(cls):
        output_dir = os.path.join(cls.CUR_DIR, "output_dir")
        if os.path.exists(output_dir):
            shutil.rmtree(output_dir)

    def setUp(self):
        if os.path.exists(self.result_dir):
            shutil.rmtree(self.result_dir)
        os.makedirs(self.result_dir)

    def tearDown(self):
        """
        Delete the data directory generated by test cases.
        """
        if os.path.exists(self.result_dir):
            shutil.rmtree(self.result_dir)

    def test_get_report_data_001(self):
        """
        Test whether the return value of get_report_data is correct when the key exists in json_data
        but the value is empty.
        """
        with open(os.path.join(self.TEST_DATA_DIR, "test_permission.json"), "rb") as file:
            json_data = json.load(file)
        pre_report = PreReport(json_data, self.option)
        self.assertIsNone(pre_report.get_report_data())

    def test_get_report_data_002(self):
        with open(os.path.join(self.TEST_DATA_DIR, "test_normal.json"), "rb") as file:
            json_data = json.load(file)
        pre_report = PreReport(json_data, self.option)
        self.assertIsInstance(pre_report.get_report_data(), ReportData)

    def test_get_machine_info_001(self):
        """
        Construct an exception and check whether the get_machine_info method
        can properly process the exception.
        """
        pre_report = PreReport(self.base_json_data, self.option)
        self.assertIsNone(pre_report.get_machine_info())

    def test_get_machine_info_002(self):
        """
        Construct complete system information and running data and
        check whether the get method can obtain the overview information.
        """
        with open(os.path.join(self.TEST_DATA_DIR, "test_machine_info.json"), "rb") as file:
            json_data = json.load(file)
        pre_report = PreReport(json_data, self.option)
        res = pre_report.get_machine_info()
        self.assertIsInstance(res, dict)
        self.assertIsNotNone(res.get(ReportKey.HARDWARE).get(Options.PRODUCT_MODEL))
        self.assertIsNotNone(res.get(ReportKey.SOFTWARE).get(Options.OS))

    def test_get_bm_summary_001(self):
        """
        Construct an exception and check whether the get_bench_summary method
        can properly process the exception.
        """
        pre_report = PreReport(self.base_json_data, self.option)
        self.assertIsNone(pre_report.get_benchmark_summary())

    def test_get_bm_summary_002(self):
        """
        Construct bench_summary data and check whether the get_bench_summary method can be successfully executed.
        """
        with open(os.path.join(self.TEST_DATA_DIR, "test_bm_summary.json"), "rb") as file:
            json_data = json.load(file)
        pre_report = PreReport(json_data, self.option)
        res = pre_report.get_benchmark_summary()
        self.assertIsInstance(res, dict)
        self.assertEqual(1, res.get(Key.COPIES))

    def test_get_bm_suite_001(self):
        """
        Construct an exception and check whether the get_bench_suite method
        can properly process the exception.
        """
        pre_report = PreReport(self.base_json_data, self.option)
        self.assertIsNone(pre_report.get_benchmark_suite({}, []))

    def test_get_bm_suite_002(self):
        """
        Construct bench_detail data and check whether the get_bench_suite method can be successfully executed.
        no sub_suites
        """
        bm_summary = {Key.SCORE: ""}
        bm_suite_list = [{"sub_suites": [], "name": "ServerSuite", "type": 0, "score": 0, "valid": True}]
        pre_report = PreReport(self.base_json_data, self.option)
        pre_report.mode_suite = "ServerSuite"
        res = pre_report.get_benchmark_suite(bm_summary, bm_suite_list)
        self.assertEqual(BM_SUITE_1, res)

    def test_get_bm_suite_003(self):
        """
        Construct bench_detail data and check whether the get_bench_suite method can be successfully executed.
        """
        bm_summary = {Key.SCORE: ""}
        bm_suite_list = [{"workloads": [], "name": "MemSuite", "score": 2.142}]
        pre_report = PreReport(self.base_json_data, self.option)
        pre_report.mode_suite = "ServerSuite"
        res = pre_report.get_benchmark_suite(bm_summary, bm_suite_list)
        self.assertEqual(BM_SUITE_2, res)

    def test_get_bm_detail_001(self):
        """
        Construct an exception and check whether the get_bench_detail method
        can properly process the exception.
        """
        pre_report = PreReport(self.base_json_data, self.option)
        self.assertEqual({}, pre_report.get_benchmark_detail([]))

    def test_get_bm_detail_002(self):
        bm_suite_list = [{"sub_suites": [{
                                "workloads": [{
                                        "name": "scimarkj_fft",
                                        "desc": "",
                                        "score": 0.0,
                                        "index": 0.0,
                                        "unit": "",
                                        "valid": False,
                                        "elapsed_time": 0.028}],
                                "name": "CPUSuite",
                                "type": 0,
                                "score": 0,
                                "valid": False}],
                          "name": "DesktopSuite",
                          "type": 0,
                          "score": 16.8602,
                          "valid": False}]
        pre_report = PreReport(self.base_json_data, self.option)
        pre_report.mode_suite = "ServerSuite"
        self.assertEqual(BM_DETAIL_1, pre_report.get_benchmark_detail(bm_suite_list))

    def test_get_bm_detail_003(self):
        """
        Construct bench_detail data and check whether the get_bench_detail method can be successfully executed.
        """
        bm_suite_list = [{'workloads': [{'name': 'scimarkj_fft', 'desc': '', 'score': 0.0, 'index': 0.0, 'unit': '',
                                         'valid': False, 'elapsed_time': 0.028}],
                          'name': 'CPUSuite', 'type': 0, 'score': 0, 'valid': False, 'desc': ''}]
        pre_report = PreReport(self.base_json_data, self.option)
        pre_report.mode_suite = "ServerSuite"
        self.assertEqual(BM_DETAIL_2, pre_report.get_benchmark_detail(bm_suite_list))

    def test_process_bm_data_001(self):
        bm_data = deepcopy(BM_DETAIL_1)
        pre_report = PreReport(self.base_json_data, self.option)
        pre_report.mode_suite = "DesktopSuite"
        self.assertEqual(BM_DETAIL_1, pre_report.process_bm_data(bm_data))

    def test_process_bm_data_002(self):
        bm_data = deepcopy(BM_DETAIL_2)
        pre_report = PreReport(self.base_json_data, self.option)
        pre_report.mode_suite = "ServerSuite"
        self.assertEqual(BM_DETAIL_2, pre_report.process_bm_data(bm_data).get("ServerSuite"))

    def test_get_sub_suite(self):
        """
        Construct an exception and check whether the get_sub_suite method
        can properly process the exception.
        """
        pre_report = PreReport(self.base_json_data, self.option)
        suite_dict = {}
        pre_report.get_sub_suites({}, suite_dict)
        self.assertEqual({}, suite_dict)

    def test_get_workloads_001(self):
        """
        Construct an exception and check whether the get_workloads method
        can properly process the exception.
        """
        pre_report = PreReport(self.base_json_data, self.option)
        workloads_dict = {}
        pre_report.get_workloads({}, workloads_dict)
        self.assertEqual({}, workloads_dict)

    def test_get_workload_002(self):
        """
        Construct workloads data and check
        whether the get_workloads method can be successfully executed.
        """
        pre_report = PreReport(self.base_json_data, self.option)
        workloads_dict = {}
        suite_res = {'workloads': [{'name': 'redis', 'desc': 'redis benchmark', 'score': 1136581.88,
                                    'index': 17.0108, 'unit': 'rps', 'valid': True, 'elapsed_time': 124.287}],
                     'name': 'ComplexSuite', 'type': 0, 'score': 17.0108, 'valid': True}
        pre_report.get_workloads(suite_res, workloads_dict)
        self.assertEqual(WORKLOAD_INFO, workloads_dict)

    def test_get_testcase_status(self):
        with open(os.path.join(self.TEST_DATA_DIR, "test_normal.json"), "rb") as file:
            json_data = json.load(file)
        pre_report = PreReport(json_data, self.option)
        pre_report.mode_suite = "ServerSuite"
        bm_data = pre_report.process_bm_data(pre_report.get_benchmark_detail(pre_report.bm_detail))
        self.assertEqual([8, 6, 2], pre_report.get_testcase_status(bm_data))


if __name__ == "__main__":
    suite = unittest.TestLoader().loadTestsFromTestCase(PreReportTestCase)
    unittest.TextTestRunner(verbosity=2).run(suite)
